/***************************************************************
*  Name:  rsa_test
*	    
*  Synopsis:  rsa test routines
*    	    
*  Description:
*     	    
*  History:
*      	         dietrich - Jan 18, 2012:  Created.
*
*
***************************************************************/

/* $Id: rsa.c,v 1.4 2012/01/21 20:04:07 pascal Exp pascal $ */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gmp.h>
#include <time.h>
#include "rsa.h"

/* compile with  gcc -DF_TEST_RSA   */

void test_genprime(int minb, int maxb)
{
	mpz_t prime, r;

	mpz_init(prime);
	printf("Gen prime of min %d to max %d bits\n",minb, maxb);
	genprime(prime, minb, maxb);
	puts("Result of genprime:");
	mpz_out_str(stdout, 10, prime);
        puts("");
}


void test_modinv(int  d, int m)
{
	mpz_t gd, gm, r;
	int ret;
	
	mpz_init(gd);
	mpz_init(gm);
	mpz_init(r);
	
	mpz_set_ui(gd,d);
	mpz_set_ui(gm,m);

	puts("d:");mpz_out_str(stdout, 10, gd);puts("");
	puts("m:");mpz_out_str(stdout, 10, gm);puts("");	

	ret = mod_inv(r, gd, gm);

	printf("ret = %d\n",ret);

	puts("mod inv:");
	mpz_out_str(stdout, 10, r);
	puts("");
}



void test_rsa_key(int keylen)
{
	mpz_t exp, mod, priv;
	int res;

	res = gen_rsa_keys(keylen, exp, mod, priv);

	printf("gen_rsa_keys()->%d\n",res);
	mpz_printf("exp ",exp);
	mpz_printf("mod ",mod);
	mpz_printf("priv",priv);

	//encrypt;
	mpz_t text;
	mpz_t cipher;
	mpz_t decipher;

	mpz_init(text);
	mpz_init(cipher);
	mpz_init(decipher);

	mpz_set_ui(text, 1234456);
	mpz_printf("input text",text);
	mpz_powm(cipher, text, exp, mod);
	mpz_printf("cipher text",cipher);
	mpz_powm(decipher,cipher,priv,mod);
	mpz_printf("decipher",decipher);
	
}

#ifdef F_OLD_KEY
void test_rsa_load()
{
	mpz_t exp, mod;
	rsa_key * key1;

	key1 = (rsa_key*) malloc(sizeof(rsa_key)+4);
	key1->explen=2;
	key1->modlen=2;
	key1->key[0]=1;
	key1->key[1]=1;	
	key1->key[2]=1;
	key1->key[3]=2;	
	
	mpz_import_key(key1, exp, mod);
	
}
#endif


void keydump(rsa_key_t * key, char * name)
{
#ifdef F_OLD_KEY	
	printf("key %s:explen %d, modlen %d\n",name,key->explen,key->modlen);
	memdump("exp",key->key,key->explen);
	memdump("mod",key->key+key->explen,key->modlen);
#endif
	printf("keydump:%s\n",name);
	
	mpz_printf16("exp",key->exponent);
	mpz_printf16("mod",key->modulus);
}


#if F_OLD_KEY
void test_rsa_unload()
{
	mpz_t exp, mod;
	rsa_key * key;


	mpz_init(exp);
	mpz_init(mod);

	mpz_set_ui(exp, 124567);
	mpz_set_ui(mod, 5674432);

	key = mpz_export_key(exp, mod);

	mpz_printf16("exp",exp);
	mpz_printf16("mod",mod);

	keydump(key,"test key");
}


rsa_key * alloc_rsa_key(size_t esz,  size_t msz)
{
	rsa_key *  key = malloc(sizeof(rsa_key)+esz+msz-1);
	key->explen = esz;
	key->modlen = msz;
	return key;
}

void test_rsa_load_unload(size_t esz,  size_t msz)
{
	rsa_key * key, *key2;
	mpz_t sexp, smod;
	mpz_t rexp, rmod;	

	key = alloc_rsa_key(esz, msz);

	/* fill with randow */
	int k;
	for (k=0; k<esz+msz; k++)
		key->key[k]=rand();

	keydump(key,"randkey");

	mpz_init(sexp);
	mpz_init(smod);
	mpz_init(rexp);
	mpz_init(rmod);

	mpz_import_key(key,sexp,smod);

	mpz_printf16("sexp",sexp);
	mpz_printf16("smod",smod);

	key2 = mpz_export_key(sexp,smod);
	
	keydump(key2, "key2");
	
}
#endif


void test_mpz_load_unload(size_t sz)
{
	unsigned char * buf;
	mpz_t num;	

	buf = (char*)malloc(sz);

	/* fill with randow */
	int k;
	for (k=0; k<sz; k++)
		buf[k]=rand();

	memdump("initial buf",buf,sz);

	mpz_init(num);

	mpz_import_buf(buf,sz, num);

	mpz_printf16("num",num);

	int rsz = mpz_export_buf(0, 0, num);

	char * buf2 = malloc(rsz);

	rsz = mpz_export_buf(buf2, rsz, num);	
	
	memdump("final buf",buf2,rsz);

	if (sz != rsz) {
		printf("\nBuffers size is  different\n");
	}
	if (memcmp(buf,buf2,sz))
		printf("\nBuffers are  different\n");
}


void test_rsa_test(int keylen, int blen)
{
  rsa_key_t  public_key[1],  private_key[1];
  int k;
  unsigned char * buf = malloc(blen);
  unsigned char * cipher, *decrypt; 
  int n;

  printf("-----------------------\n");
  rsa_generate_key(keylen, public_key,  private_key);
  printf("-----------------------\n");

  keydump(public_key,"PUBLIC_KEY");
  keydump(private_key,"PRIVATE_KEY");
    printf("-----------------------\n");
  // fill
  for (k=0; k<blen; k++) buf[k]=rand();
  memdump("input-data",buf,blen);
    printf("-----------------------\n");

  n = rsa_encrypt(buf, blen, &cipher, public_key);
  printf("-----------------------\n");
  printf("rsa_encrypt: n=%d\n",n);
  memdump("cipher",cipher,n);
    printf("-----------------------\n");
  n = rsa_decrypt(cipher, n, &decrypt, private_key);
  printf("-----------------------\n");
  printf("rsa_drecrypt: n=%d\n",n);
  

  if (n> 0) {
	  memdump("decrypt",decrypt, n);
	  printf("-----------------------\n");

  //
	  if (!memcmp(buf, decrypt, blen) )
		  printf("Buffers are the same, encrypt-decrypt succeeded\n");
	  else
		  printf("Buffers differs, encrypt-decryot failed\n");
  } else
	  printf("Decrypt error\n");
}


int main(int argc, char* argv[]) {
    mpz_t n, max, two, p;
    gmp_randstate_t rand_state;
    gmp_randinit_default(rand_state);
    gmp_randseed_ui (rand_state, time(NULL));

    if (argc <2) {
      fprintf(stderr,"rsa: a least one parameter required\n");
      exit(1);
    }
    

    if (strcmp(argv[1], "test") == 0) {
        mpz_init_set_str(n, argv[2], 10);
        puts(miller_rabin(n, rand_state) == PROBABLE_PRIME ? "PRIME" : "COMPOSITE");
    } else if (strcmp(argv[1], "genprime") == 0) {
	    int minb = atoi(argv[2]);
	    int maxb = atoi(argv[3]);
	    test_genprime(minb, maxb);
    } else if (strcmp(argv[1], "modinv") == 0) {
	    int minb = atoi(argv[2]);
	    int maxb = atoi(argv[3]);
	    test_modinv(minb, maxb);
    } else if (strcmp(argv[1], "rsakey") == 0) {
	    int keyl = atoi(argv[2]);
	    test_rsa_key(keyl);
#ifdef F_OLD_KEY	    
    } else if (strcmp(argv[1], "load") == 0) {
//	    int keyl = atoi(argv[2]);
	    test_rsa_load();
    } else if (strcmp(argv[1], "unload") == 0) {
//	    int keyl = atoi(argv[2]);
	    test_rsa_unload();
    } else if (strcmp(argv[1], "loadunload") == 0) {
	    int exp = atoi(argv[2]);
	    int mod = atoi(argv[3]);	    
	    test_rsa_load_unload(exp,mod);
#endif	    
    } else if (strcmp(argv[1], "mpzloadunload") == 0) {
	    int mod = atoi(argv[2]);	    
	    test_mpz_load_unload(mod);
    } else if (strcmp(argv[1], "rsatest") == 0) {
            int keylen = atoi(argv[2]);
      	    int datalen = atoi(argv[3]);	    
	    test_rsa_test(keylen,datalen);
    }
    
    return 0;
}



